/*
	Assignment week 2 cg 2010-2011 
	OpenGL: Transformations, viewing interaction (1)
	by Gerard Knap s1222376

	Use r-mouse down + up & down movement of the mouse to zoom in and out.
	Use l-mouse down to rotate arround the cube
	Use wasd on the keyboard for panning and zooming
*/

/*
* An OpenGL template/framework file for the Computer Graphics course
* at the University of Groningen.
*/

// If windows is used, windows.h should be included (before gl.h and glu.h)
#if defined(_WIN32)
#include <windows.h>
#endif

// If you use GLUT you do not need to include gl.h and glu.h
// as glut.h guarantees that gl.h and glu.h are properly 
// included.
// So if you do not wish to use  glut.h, uncomment the following lines.
//#include <GL/gl.h>
//#include <GL/glu.h>

#if defined(NEED_GLEW)
#include "glew.h"
#endif

// Apparently Mac OS X puts the GLUT headers somewhere different.
// For windows we use freeglut.
#if defined(__APPLE__)&& defined(__MACH__)
#include <GLUT/glut.h>
#elif defined(_WIN32)
#include <GL/freeglut.h>
#else
#include <GL/glut.h>
#endif

#include <stdlib.h>
#include <stdio.h>

#include <math.h>

#ifndef M_PI
#define M_PI           3.14159265358979323846
#endif

#define A -1.0,-1.0,-1.0	//0
#define B 1.0,-1.0,-1.0		//1
#define C 1.0,-1.0, 1.0		//2
#define D -1.0,-1.0, 1.0	//3
#define E -1.0, 1.0,-1.0	//4
#define F 1.0, 1.0,-1.0		//5
#define G 1.0, 1.0, 1.0		//6
#define H -1.0, 1.0, 1.0	//7


//vertex colors
#define AC 1.0f,0.6f,0.6f
#define BC 0.0f,0.0f,1.0f
#define CC 0.0f,1.0f,0.0f
#define DC 0.0f,1.0f,1.0f
#define EC 1.0f,0.0f,0.0f
#define FC 1.0f,0.0f,0.1f
#define GC 1.0f,1.0f,0.0f
#define HC 1.0f,0.7f,0.7f

#define SPHERE_N (20)

void idle();

//variables used to store mouse-coordinates
GLfloat startDist=0, panning=0 ;
int prevX=0, prevY=0, startX=0, startY=0;


GLfloat cubeVertices[8*3] = {A, B, C, D, E, F, G, H};

//variables used to change the viewpoint
GLfloat alt = 15, azim = 45, height = 0.5, distance = 4 ;
BOOL doZoom , doRotate ;

#if !defined true
	#define 	true   (0==0)
	#define 	false   (!true)
#endif

GLubyte cubeIndices[6*4] = {
	0,1,2,3,
	5,4,0,1,
	0,3,7,4,
	6,5,1,2,
	7,4,5,6,
	6,2,3,7
}; 

GLfloat cubeColor[] = {
	AC,BC,CC,DC,
	EC,FC,GC,HC
}; 



//if parameters like azim or alt are changed, this function wil redraw the cube with the specified params
void setViewPoint()
{
  glLoadIdentity();
  glTranslatef(panning,-height,-distance);
  glRotatef(-90+alt,1,0,0);
  glRotatef(azim,0,0,1);
}


void mouse(int btn, int state, int x, int y)
{
	startX = x;
	startY = y;
	prevX = x;
	prevY = y;

	startDist = distance;

	if(btn==GLUT_LEFT_BUTTON)  { // the l-mouse-button is voor rotating arround the cube
		doRotate = state==GLUT_DOWN;
		doZoom = false;
	}
	if(btn==GLUT_RIGHT_BUTTON)   { // the r-mouse-button is voor zooming 
		doRotate = false;
		doZoom = state==GLUT_DOWN;
	}
	if(btn==GLUT_MIDDLE_BUTTON&state==GLUT_DOWN)   { // close on middle click
		exit( 0 );
	}
}

// if the user moves the mouse... calculate how much is moved and depening if the user is zooming or rotating
//change the parameters accordingly. This function also updates prevX and prevY.
void motion(int x, int y) 
{
	int dx, dy;

	dx = startX - x;
	dy = startY - y;
	
	if(doZoom) {
		distance = (0.01 * dy) + startDist;
	} else if(doRotate) {
		azim -= 0.5 * (prevX - x);
		alt -= 0.2 * (prevY - y);
	}
 
	prevX = x;
	prevY = y;
	//printf("x: %d, y:%d, dx: %d, dy:%d\n" , x, y,dx,dy);
}
 

void setGlMaterial(GLfloat r, GLfloat g, GLfloat b, GLfloat ka, GLfloat kd, GLfloat ks, GLfloat n)
{
    GLfloat ambient[] = {ka*r,ka*g,ka*b,1.0};
    GLfloat diffuse[] = {kd*r,kd*g,kd*b,1.0};
    GLfloat specular[] = {ks,ks,ks,1.0};
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, n);
}


void display(void)
{
    /* Clear all pixels */
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    gluLookAt(200.0,200.0,1000.0,200.0,200.0,0.0,0.0,1.0,0.0);

    /* Set up other things you may need */
    /* ... */

    setGlMaterial(0.0f,0.0f,1.0f,0.2,0.7,0.5,64);
    glPushMatrix();
    glTranslated(90,320,100);
    glutSolidSphere(50,SPHERE_N,SPHERE_N);
    glPopMatrix();

    setGlMaterial(0.0f,1.0f,0.0f,0.2,0.3,0.5,8);
    glPushMatrix();
    glTranslated(210,270,300);
    glutSolidSphere(50,SPHERE_N,SPHERE_N);
    glPopMatrix();

    setGlMaterial(1.0f,0.0f,0.0f,0.2,0.7,0.8,32);
    glPushMatrix();
    glTranslated(290,170,150);
    glutSolidSphere(50,SPHERE_N,SPHERE_N);
    glPopMatrix();

    setGlMaterial(1.0f,0.8f,0.0f,0.2,0.8,0.0,1);
    glPushMatrix();
    glTranslated(140,220,400);
    glutSolidSphere(50,SPHERE_N,SPHERE_N);
    glPopMatrix();

    setGlMaterial(1.0f,0.5f,0.0f,0.2,0.8,0.5,32);
    glPushMatrix();
    glTranslated(110,130,200);
    glutSolidSphere(50,SPHERE_N,SPHERE_N);
    glPopMatrix();

    /* Whatever clean up you need */
    /* ... */

    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0,0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(2.0*atan2(h/2.0,1000.0)*180.0/M_PI,(GLdouble)w/(GLdouble)h,500,1000);
    glMatrixMode(GL_MODELVIEW);
}

/*
void display2(void)
{
    /* Clear all pixels * /
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(0.0f,0.0f,1.0f);
    glLoadIdentity();
	setViewPoint();

	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	glColorPointer(3, GL_FLOAT, 0, cubeColor);
	glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
	
	// draw a cube
	glDrawElements(GL_QUADS,24, GL_UNSIGNED_BYTE, cubeIndices);

	// deactivate vertex arrays after drawing
	glDisableClientState( GL_COLOR_ARRAY );
	glDisableClientState(GL_VERTEX_ARRAY);

    glutSwapBuffers();
	 
}*/

void idle()
{ 
	display();
}



void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
        case 'q':
        case 'Q':
        case 27: // ESC key
            printf("Exiting...\n");
            exit(0);
            break;
		case 'a':
			//panning += 0.4f;
			break;
		case 'd' :
			//panning -= 0.4f;
			break;
		case 's':
			//distance += 0.2f;
			break;
		case 'w':
			//distance -= 0.2f;
			break;
    }
}

/*
void reshape2(int w, int h)
{
    glViewport(0,0, (GLsizei) w, (GLsizei) h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0,(GLdouble)w/(GLdouble)h,1.5,20.0);
    glMatrixMode(GL_MODELVIEW);
}*/



int main(int argc, char** argv)
{
#if defined(NEED_GLEW)
    GLenum err;
#endif


    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    //glutInitWindowSize(800,600);
	glutInitWindowSize(400,400);
    glutInitWindowPosition(220,100);
    glutCreateWindow("Computer Graphics - OpenGL framework");

#if defined(NEED_GLEW)
    /* Init GLEW if needed */
    err = glewInit();
    if (GLEW_OK != err) {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
        exit(1);
    }
    fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
#endif

    /* Select clearing (background) color */
    glClearColor(0.0,0.0,0.0,0.0);
    //glShadeModel(GL_FLAT);
	glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);

    /* Register GLUT callback functions */
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutReshapeFunc(reshape);

	glutIdleFunc(idle);
	glutMouseFunc(mouse);
	glutMotionFunc(motion);
    glutMainLoop();

    return 0;
}
